// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#pragma once
#include <string>
#include <type_traits>
#include "registry.h"
#include "melon/dynamic.h"
#include "melon/hash/hash.h"

namespace kumo {
    namespace pollux {
        class ISerializable;

        using DeserializationRegistryType = Registry<
            std::string,
            std::shared_ptr<const ISerializable>(const melon::Dynamic &)>;

        DeserializationRegistryType &DeserializationRegistryForSharedPtr();

        using DeserializationWithContextRegistryType = Registry<
            std::string,
            std::shared_ptr<const ISerializable>(const melon::Dynamic &, void *context)>;

        DeserializationWithContextRegistryType &
        DeserializationWithContextRegistryForSharedPtr();

        using DeserializationRegistryUniquePtrType = Registry<
            std::string,
            std::unique_ptr<ISerializable>(const melon::Dynamic &)>;

        DeserializationRegistryUniquePtrType &deserializationRegistryForUniquePtr();

        namespace detail {
            template<class, class = void>
            struct is_templated_create : std::false_type {
            };

            template<class T>
            struct is_templated_create<
                        T,
                        std::void_t<decltype(T::template create<T>(
                            std::declval<melon::Dynamic>()))> > : std::true_type {
            };
        } // namespace detail

        template<class T>
        void registerDeserializer() {
            if constexpr (detail::is_templated_create<T>::value) {
                DeserializationRegistryForSharedPtr().Register(
                    T::getClassName(), T::template create<T>);
            } else {
                DeserializationRegistryForSharedPtr().Register(
                    T::getClassName(), T::create);
            }
        }
    } // namespace pollux
} // namespace kumo
